%{
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <float.h> 
  //#include "grammar.y.h"
#define BUFSIZE 1024
#define ID_INT 4
#define RO_INT 5
#define RO_FLOAT 6
#define ID_FLOAT 1
#define ID_VOID 2
#define NOINIT 3

#ifdef DBL_DECIMAL_DIG 
#define OP_DBL_Digs (DBL_DECIMAL_DIG) 
#else 
#ifdef DECIMAL_DIG 
#define OP_DBL_Digs (DECIMAL_DIG) 
#else 
#define OP_DBL_Digs (DBL_DIG + 3) 
#endif 
#endif 

  FILE *driver;
	
  extern int yylineno;
  int yylex ();
  int yyerror ();
  char elseDrive[20000];
  char tmpC[200];
  int tabHash[BUFSIZE];
  char n_reg[BUFSIZE];
 	char tabFonction[BUFSIZE][BUFSIZE];
  char tabFonctionNom[BUFSIZE][BUFSIZE];
  int tmp;
  int pos;
  float posf;
  int glob_type = 0;
  int glob_fonction = 0;
  int static_var[5];
	
  int new_reg(){
    static int i = 0;
    i++;
    return i%BUFSIZE;
  }
	
  int hash(char *s){
    int r=0;
    while(s[0] != '\0'){
      r+=s[0];
      s++;
    }
    return(r%BUFSIZE);
  }

  char * translate(int i){
    if (i==ID_INT)
      return "i32";
    else if (i==ID_FLOAT)
      return "float";
    else if (i==ID_VOID)
      return "void";
    else
      return "erreur";
  }

  int in_static_array(char *input){
    char *temp[] = {"%gear","%accelCmd","%steer","%clutchCmd","%brakeCmd"};
    int i=0;
    for(i=0;i<5;i++){
      if(strcmp(input, temp[i])==0){
	return i;
      }
    }
    return -1;
  }

  void ajout_store_manquant(){
    char *temp[] = {"store i32 1, i32* %gear","store float 0.000000e+00, float* %accelCmd","store float 0.000000e+00, float* %steer","store float 0.000000e+00, float* %clutchCmd","store float 0.000000e+00, float* %brakeCmd"};
    int i=0;
    strcpy(tmpC, "");
    for(i=0;i<5;i++){
      if(static_var[i]==0){
	strcat(tmpC, temp[i]);
	strcat(tmpC, "\n");
      }
    }
    return;
  }


  %}

%union{char *id; struct str{char code[10000];int type; char reg[10000];} st;}
%token<id> CONSTANTI
%token<id> CONSTANTF
%token<id> INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
%token<id> IF ELSE WHILE RETURN FOR

%token<id> IDENTIFIER INT FLOAT VOID TYPE_NAME
%token<id> SUB_ASSIGN MUL_ASSIGN ADD_ASSIGN

%type<st> type_name declarator function_definition compound_statement declaration_list statement_list declarator_list argument_expression_list
%type<st> statement expression_statement expression unary_expression assignment_operator comparison_expression
%type<st> postfix_expression primary_expression multiplicative_expression additive_expression parameter_list unary_operator
%type<st> declaration selection_statement iteration_statement jump_statement program external_declaration parameter_declaration

%start program
%%

primary_expression
: IDENTIFIER           {sprintf(tmpC, "%%%s", $1); strcpy($$.reg, tmpC); strcpy($$.code,""); $$.type = NOINIT;}
| CONSTANTI            {strcpy($$.code, $1); $$.type = ID_INT; strcpy($$.reg, "");}
| CONSTANTF            {sprintf($$.code, "%.*e", OP_DBL_Digs - 1, strtof($1,NULL)); $$.type = ID_FLOAT; strcpy($$.reg, "");}
| '(' expression ')'   {strcpy($$.code, $2.code); strcpy($$.reg, "");}

| IDENTIFIER '(' ')'                          {
  sprintf($$.reg, "%%r%d", new_reg()); 
  sprintf($$.code, "%s = call %s @%s()\n", $$.reg, translate(glob_type), $1); 
	sprintf(tabFonction[glob_fonction], "declare %s @%s()", translate(glob_type), $1);
  sprintf(tabFonctionNom[glob_fonction], "%s", $1);
  glob_fonction++;
  $$.type = glob_type;}

| IDENTIFIER '(' argument_expression_list ')' {
  sprintf($$.reg, "%%r%d", new_reg()); 
  sprintf($$.code, "%s = call %s @%s(%s)", $$.reg, translate(glob_type), $1, $3.code);
	sprintf(tabFonction[glob_fonction], "declare %s @%s(%s)", translate(glob_type), $1, $3.code);
  sprintf(tabFonctionNom[glob_fonction], "%s", $1);
  glob_fonction++;
  $$.type = glob_type;}

| IDENTIFIER INC_OP {
  sprintf(tmpC, "%%%s", $1);
  sprintf($$.reg, "%%r%d", new_reg()); 
  $$.type = tabHash[hash(tmpC)];
  if (tabHash[hash(tmpC)]==ID_INT)
    sprintf($$.code, "%s = add i32 %%%s, 1\n", $$.reg, $1);
  else if (tabHash[hash(tmpC)]==ID_FLOAT)
    sprintf($$.code, "%s = fadd float %%%s, 1.000000e+00\n", $$.reg, $1);
  else{
    yyerror(NULL);
    exit(EXIT_FAILURE);}}

| IDENTIFIER DEC_OP {
  sprintf(tmpC, "%%%s", $1);
  $$.type = tabHash[hash(tmpC)];
  sprintf($$.reg, "%%r%d", new_reg()); 
  if (tabHash[hash(tmpC)]==0)
    sprintf($$.code, "%s = sub i32 %%%s, 1\n", $$.reg, $1);
  else if (tabHash[hash(tmpC)]==1)
    sprintf($$.code, "%s = fsub float %%%s, 1.000000e+00\n", $$.reg, $1);
  else{
     yyerror(NULL);
     exit(EXIT_FAILURE);}}
;

postfix_expression
: primary_expression                    {strcpy($$.code, $1.code); strcpy($$.reg, $1.reg);
   if ($1.type == NOINIT){
     $$.type = tabHash[hash($1.reg)];
     glob_type = tabHash[hash($1.reg)];
   }else 
     $$.type = $1.type;}
| postfix_expression '[' expression ']' {//MODIF TABLEAU
  char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
                                                   $$.type = $1.type;
                                                   strcpy($$.reg,"%r");
                                                   strcat($$.reg, n_reg);
						   strcpy($$.code, "%r");
                                                   strcat($$.code, n_reg);
                                                   strcat($$.code, " = getelementptr ");
						   sprintf(n_reg, "%s", translate($1.type));
						   strcat($$.code, n_reg);
						   strcat($$.code, "* ");
						   strcat($$.code, $1.reg);
						   strcat($$.code, ", ");
						   sprintf(n_reg, "%s", translate($3.type));
						   strcat($$.code, n_reg);
						   strcat($$.code, " ");
						   if(strcmp($3.reg,"")==0)
						     strcat($$.code, $3.code);
						   else
						     strcat($$.code, $3.reg);
						   strcat($$.code, "\n");
						   sprintf(n_reg, "%%r%d", new_reg());
						   strcat($$.code, n_reg);
						   strcat($$.code, " = load ");
						   char tmpTab[BUFSIZE];
						   sprintf(tmpTab, "%s", translate($1.type));
						   strcat($$.code, tmpTab);
						   strcat($$.code, "* ");
						   strcat($$.code, $$.reg);
						   strcpy($$.reg, n_reg);
						   strcat($$.code, "\n");
						   //
  }
;

argument_expression_list
: primary_expression {
	int type;
	char tmp1[100];
	if ($1.type == NOINIT){
		type = tabHash[hash($1.reg)];
		strcpy(tmp1, $1.reg);
	}else{
		type = $1.type;
		strcpy(tmp1, $1.code);
	}
	sprintf($$.code, "%s %s", translate(type), tmp1);
	strcpy($$.reg, $1.reg);
	$$.type = $1.type;
}
| argument_expression_list ',' primary_expression {
	int type1;
	char tmp1[100];
	if ($3.type == NOINIT){
		type1 = tabHash[hash($3.reg)];
		strcpy(tmp1, $3.reg);
	}else{
		type1 = $3.type;
		strcpy(tmp1, $3.code);
	}
	sprintf(tmpC, "%s, %s %s", $1.code, translate(type1), tmp1);
	strcpy($$.code, tmpC);
	strcpy($$.reg, $1.reg);
	strcpy($$.code, tmpC);
	$$.type = $1.type;
}
;

unary_expression
: postfix_expression                {strcpy($$.code, $1.code); strcpy($$.reg, $1.reg); $$.type = $1.type;}
| INC_OP unary_expression {
  sprintf($$.reg, "%%%d", new_reg()); 
  $$.type = $2.type;
  if ($2.type == 0)
    sprintf($$.code, "%s \n %s = add %s, 1\n", $2.code, $$.reg, $2.reg);
  else if ($2.type == 1)
    sprintf($$.code, "%s \n %s = fadd %s, 1.000000e+00\n", $2.code, $$.reg, $2.reg);
  else{
     yyerror(NULL);
     exit(EXIT_FAILURE);}}
 
| DEC_OP unary_expression {
  sprintf($$.reg, "%%%d", new_reg()); 
  $$.type = $2.type;
  if ($2.type == 0)
    sprintf($$.code, "%s \n %s = sub %s, 1\n", $2.code, $$.reg, $2.reg);
  else if ($2.type == 1)
    sprintf($$.code, "%s \n %s = fsub %s, 1.000000e+00\n", $2.code, $$.reg, $2.reg);
  else{
    yyerror(NULL);
    exit(EXIT_FAILURE);}}

| unary_operator unary_expression {
  sprintf(tmpC, "%%%d", new_reg()); strcpy($$.reg,tmpC);
  $$.type = $2.type;
  if ($2.type == 0)
    sprintf($$.code, "%s \n %s = sub 0, %s\n", $1.code, $$.reg, $2.reg);
  else if ($2.type == 1)
    sprintf($$.code, "%s \n %s = fsub 0.000000e+00, %s\n", $1.code, $$.reg, $2.reg);
  else{
    yyerror(NULL);
    exit(EXIT_FAILURE);}}
;

unary_operator
: '-' {strcpy($$.code, "-");}
;


multiplicative_expression
: unary_expression                                {strcpy($$.reg, $1.reg); strcpy($$.code, $1.code); $$.type = $1.type;}
| multiplicative_expression '*' unary_expression  {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcpy($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = mul i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fmul float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Erreur de compatibilité *\n");
      yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| multiplicative_expression '/' unary_expression  {sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = div i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fdiv float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Erreur de compatibilité /\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
;

additive_expression
: multiplicative_expression                      {strcpy($$.reg, $1.reg); strcpy($$.code, $1.code); $$.type = $1.type;}
| additive_expression '+' multiplicative_expression   {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = add i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fadd float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Erreur de compatibilité +\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression '-' multiplicative_expression    {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = sub i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fsub float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Erreur de compatibilité -\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
;

comparison_expression
: additive_expression                           {strcpy($$.reg, $1.reg); strcpy($$.code, $1.code); $$.type = $1.type;}
| additive_expression '<' additive_expression   {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcpy($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp slt i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp olt float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (6)\n");
      yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression '>' additive_expression   {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp sgt i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp ogt float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (5)\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression LE_OP additive_expression {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp sle i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp ole float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (4)\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression GE_OP additive_expression {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp sge i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp oge float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (3)\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression EQ_OP additive_expression {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp eq i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp oeq float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (2)\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
| additive_expression NE_OP additive_expression {char n_reg[BUFSIZE]; sprintf(n_reg, "%d", new_reg());
   $$.type = $1.type;
   strcpy($$.reg,"%r");
   strcat($$.reg, n_reg);
   strcpy($$.code, "");
   if(strcmp($1.reg,"") != 0){
     strcat($$.code, $1.code);
     strcat($$.code, "\n");
   }
   else if(strcmp($3.reg,"") != 0){
     strcat($$.code, $3.code);
     strcat($$.code, "\n");
   }
   strcat($$.code, "%r");
   strcat($$.code, n_reg);
   if(($1.type == ID_INT)&&($3.type == ID_INT)){
     strcat($$.code, " = icmp ne i32 ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else if(($1.type == ID_FLOAT)&&($3.type == ID_FLOAT)){
     strcat($$.code, " = fcmp one float ");
     if(strcmp($1.reg,"") != 0)
       strcat($$.code, $1.reg);
     else
       strcat($$.code, $1.code);
     strcat($$.code, ", ");
     if(strcmp($3.reg,"") != 0)
       strcat($$.code, $3.reg);
     else
       strcat($$.code, $3.code);
   }else{
     printf("Les comparaisons doivent se faire entre deux types identiques (1)\n");
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }}
;

expression
: unary_expression assignment_operator comparison_expression  {
  int j;
  if(($1.type == RO_INT)||($1.type == RO_FLOAT)){
    printf("Ecriture dans variable en lecture seule impossible\n");
    yyerror(NULL);
    exit(EXIT_FAILURE);
  }
  if(((j=in_static_array($1.reg))!= -1)&&(!static_var[j])){
    strcpy($$.code, "store ");
    if(strcmp($2.code,"=")==0){
      if(($3.type == ID_INT)&&($1.type == ID_INT)){
	strcat($$.code, "i32 ");
	if(!strcmp($3.reg,""))
	  strcat($$.code, $3.code);
	else
	  strcat($$.code, $3.reg);
	strcat($$.code, ", i32* ");
      }else if(($3.type == ID_FLOAT)&&($1.type == ID_FLOAT)){
	strcat($$.code, "float ");
	if(!strcmp($3.reg,""))
	  strcat($$.code, $3.code);
	else
	  strcat($$.code, $3.reg);
	strcat($$.code, ", float* ");
      } else {
	printf("L'affectation doit se faire entre deux types identiques\n ");
	yyerror(NULL);
	exit(EXIT_FAILURE);
      }
      strcat($$.code, $1.reg);
      strcat($$.code, "\n");
    }
    static_var[j]=1;
  } else {
    strcpy($$.reg, "%");
    strcat($$.reg, $1.code);
    if(strcmp($3.reg,""))
      strcpy($$.code, $3.code);
    else
      strcpy($$.code, "");
    strcat($$.code, "\n");
    if(strcmp($2.code,"=")==0){
      //MODIF TABLEAU
      strcat($$.code, $1.code);
      strcat($$.code, "\n");
      strcat($$.code, $1.reg);
      //strcat($$.code, $1.reg);
      //
      if(($3.type == ID_INT)&&($1.type == ID_INT)){
	strcat($$.code, " = add i32 ");
      }else if(($3.type == ID_FLOAT)&&($1.type == ID_FLOAT)){
	strcat($$.code, " = fadd float ");
      } else {
	printf("L'affectation doit se faire entre deux types identiques\n ");
	yyerror(NULL);
	exit(EXIT_FAILURE);
      }
      if(!strcmp($3.reg,""))
	strcat($$.code, $3.code);
      else
	strcat($$.code, $3.reg);
      if($3.type == ID_INT)
	strcat($$.code, ", 0");
      else
	strcat($$.code, ", 0.000000e+00");
    }
  }
 }
| comparison_expression  {strcpy($$.code, $1.code); strcpy($$.reg, $1.reg);}
;

assignment_operator
: '='           {strcpy($$.code, "=");}
| MUL_ASSIGN    {strcpy($$.code, $1);}
| ADD_ASSIGN    {strcpy($$.code, $1);}
| SUB_ASSIGN    {strcpy($$.code, $1);}
;

declaration
: type_name declarator_list ';'     {
  if(strncmp($2.code, "%", 1)==0) 
    strcpy($$.code, $2.code); 
  else 
    strcpy($$.code,"");
 }
;

declarator_list
: declarator                        {
   //MODIF TABLEAU
   strcpy($$.code, $1.code);
//
 }
| declarator_list ',' declarator    {
   //MODIF TABLEAU
   strcpy($$.code, $1.code); strcat($$.code, $3.code);
   //
}
;

type_name
: VOID {
  glob_type = ID_VOID;
  strcpy($$.code, "void");
 }
| INT {
  glob_type = ID_INT;
  strcpy($$.code, "i32");
  }
| FLOAT {
  glob_type = ID_FLOAT;
  strcpy($$.code, "float");
  }
;

declarator
: IDENTIFIER                          {
  sprintf(tmpC, "%%%s", $1);
  if(tabHash[hash(tmpC)] == NOINIT){ 
    tabHash[hash(tmpC)] = glob_type; 
    strcpy($$.code, $1);
    strcpy($$.reg, tmpC);
  } 
  else {
    printf("Erreur : variable %s deja declaree (ou probleme de table de hashage)\n", tmpC); 
    yyerror(NULL); 
    exit(EXIT_FAILURE);}}

| '(' declarator ')'                  {
  if(strcmp($2.code, "drive")==0) 
    strcpy($$.code, $2.code); 
  else{
    sprintf(tmpC, "( %s )", $2.code); 
    strcpy($$.code, tmpC);}}

| declarator '[' CONSTANTI ']'        {
  if(strcmp($1.code, "drive")==0) 
    strcpy($$.code, $1.code); 
  else{
    sprintf($$.code, "%s = alloca [%s x %s]\n", $1.reg, $3, translate(tabHash[hash($1.reg)])); 
    strcpy($$.reg, $1.reg); 
    $$.type = tabHash[hash($1.reg)];
  }}

| declarator '[' ']'                  {if(strcmp($1.code, "drive")==0) strcpy($$.code, $1.code); else{sprintf(tmpC, "%s [ ]", $1.code); strcpy($$.code, tmpC);}}

| declarator '(' parameter_list ')'   {if(strcmp($1.code, "drive")==0) strcpy($$.code, $1.code); else{sprintf(tmpC, "%s ( %s )", $1.code, $3.code); strcpy($$.code, tmpC);}}

| declarator '(' ')'                  {if(strcmp($1.code, "drive")==0) strcpy($$.code, $1.code); else{sprintf(tmpC, "%s ( )", $1.code); strcpy($$.code, tmpC);}}
;

parameter_list
: parameter_declaration                     {strcpy($$.code, $1.code); $$.type = $1.type;}
| parameter_list ',' parameter_declaration  {sprintf(tmpC, "%s , %s", $1.code, $3.code); strcpy($$.code, tmpC); $$.type = $1.type;}
;

parameter_declaration
: type_name declarator    {$$.type = glob_type;if(glob_type==1){sprintf(tmpC, "float %%%s",$2.code); strcpy($$.code, tmpC);}
   else if(glob_type==2){sprintf(tmpC, "void %%%s",$2.code); strcpy($$.code, tmpC);}
   else if(glob_type==4){sprintf(tmpC, "i32 %%%s",$2.code); strcpy($$.code, tmpC);}
   else exit(EXIT_FAILURE);
 }
;

statement
: compound_statement   {strcpy($$.code, $1.code); $$.type = $1.type;}
| expression_statement {strcpy($$.code, $1.code); $$.type = $1.type;}
| selection_statement  {strcpy($$.code, $1.code); $$.type = $1.type;}
| iteration_statement  {strcpy($$.code, $1.code); $$.type = $1.type;}
| jump_statement       {strcpy($$.code, $1.code); $$.type = $1.type;}
;

compound_statement
: '{' '}'               {strcpy($$.code, "");}
| '{' statement_list '}' {strcpy($$.code, $2.code); $$.type = $2.type;}
| '{' declaration_list statement_list '}' {
  strcpy($$.code, $2.code); strcat($$.code, $3.code); $$.type = $2.type;
  }
;

declaration_list
: declaration                        {strcpy($$.code, $1.code); $$.type = $1.type;}
| declaration_list declaration       {sprintf(tmpC, "%s \n%s", $1.code, $2.code); strcpy($$.code, tmpC); $$.type = $1.type;}
;

statement_list
: statement                          {strcpy($$.code, $1.code);}
| statement_list statement           {tmp = new_reg(); sprintf($$.code, "%s \n%s", $1.code, $2.code);}
;

expression_statement
: ';'                {strcpy($$.code, "");}
| expression ';'     {strcpy($$.code, $1.code);}
;

selection_statement
: IF '(' expression ')' statement {
  tmp = new_reg(); 
  sprintf($$.code, "%s \n br i1 %s, label %%ifvrai%d, label %%endif%d \n\n ifvrai%d:%s \n br label %%endif%d \n  endif%d: \n\n", $3.code, $3.reg, tmp, tmp, tmp, $5.code, tmp, tmp); 
  $$.type = $3.type;} 

| IF '(' expression ')' statement ELSE statement {
  tmp = new_reg(); 
  sprintf($$.code, "%s \n br i1 %s, label %%ifvrai%d, label %%iffaux%d \n\n ifvrai%d:%s \n br label %%endif%d \n iffaux%d:%s \n br label %%endif%d \n endif%d: \n", $3.code, $3.reg, tmp, tmp, tmp, $5.code, tmp, tmp, $7.code, tmp, tmp);
  $$.type = $3.type;}

| FOR '(' expression_statement expression_statement expression ')' statement  {
  tmp = new_reg(); 
  sprintf($$.code, "%s \n %s \n br i1 %s, label %%ifvrai%d, label %%iffaux%d \n ifvrai%d: \n %s \n %s \n %s \n br i1 %s, label %%ifvrai%d, label %%iffaux%d  \n iffaux%d: \n br label %%endif%d \n endif%d: \n", $3.code, $4.code, $4.reg, tmp, tmp, tmp, $7.code, $5.code, $4.code, $4.reg, tmp, tmp, tmp, tmp, tmp); 
  $$.type = $3.type;} 
;

iteration_statement
: WHILE '(' expression ')' statement  {tmp = new_reg(); sprintf($$.code, "while%d: \n br i1 %s, label %%wvrai%d \n wvrai%d: \n %s \n label %%while%d\n\n", tmp, $3.code, tmp, tmp, $5.code, tmp);}
;

jump_statement
: RETURN ';'            {strcpy($$.code, "ret void");}
| RETURN expression ';' {strcpy($$.code, "ret "); if($2.type==4) strcat($$.code, "i32 ");
   else if($2.type==1) strcat($$.code, "float ");
   else{
     yyerror(NULL);
     exit(EXIT_FAILURE);
   }
   if(strcmp($2.reg,"")==0)
     strcat($$.code, $2.code);
   else
     strcat($$.code, $2.reg);

 }
;

program
: external_declaration         {strcpy($$.code, $1.code);}
| program external_declaration {tmp = new_reg(); sprintf(tmpC, "%s \n%s", $1.code, $2.code); strcpy($$.code, tmpC);}
;

external_declaration
: function_definition          {strcpy($$.code, $1.code);}
| declaration                  {strcpy($$.code, $1.code);}
;

function_definition
: type_name declarator compound_statement                        
{   tmp = new_reg(); 
  if(strcmp($2.code, "drive")==0){
    strcpy($2.code, "drive(i32 %index, %struct.CarElt* %car, %struct.Situation* %s)");
    strcat(elseDrive, "{\n");
    strcat(elseDrive, "\n");
    strcat(elseDrive, "    %ctrl   = getelementptr %struct.CarElt* %car, i32 0, i32 5 \n");
    strcat(elseDrive, "    %public_car = getelementptr %struct.CarElt* %car, i32 0, i32 2 \n");
    strcat(elseDrive, "    %pos    = getelementptr %struct.tPublicCar* %public_car, i32 0, i32 3 \n");
    strcat(elseDrive, "    %seg.addr = getelementptr %struct.tTrkLocPos* %pos, i32 0, i32 0 \n");
    strcat(elseDrive, "    %seg    = load %struct.trackSeg** %seg.addr \n");
    strcat(elseDrive, "\n");
    strcat(elseDrive, "    %steer    = getelementptr %struct.tCarCtrl* %ctrl, i32 0, i32 0 \n");
    strcat(elseDrive, "    %accelCmd = getelementptr %struct.tCarCtrl* %ctrl, i32 0, i32 1 \n");
    strcat(elseDrive, "    %brakeCmd = getelementptr %struct.tCarCtrl* %ctrl, i32 0, i32 2 \n");
    strcat(elseDrive, "    %clutchCmd  = getelementptr %struct.tCarCtrl* %ctrl, i32 0, i32 3 \n");
    strcat(elseDrive, "    %gear   = getelementptr %struct.tCarCtrl* %ctrl, i32 0, i32 4 \n");
    strcat(elseDrive, "\n");
    // strcat(elseDrive, "    %road_angle = call float @get_track_angle(%struct.tTrkLocPos* %pos) \n");
    //strcat(elseDrive, "    %car_angle  = call float @get_car_yaw(%struct.CarElt* %car) \n");
    //strcat(elseDrive, "    %angle    = fsub float %road_angle, %car_angle \n");
    //strcat(elseDrive, "    %nangle   = call float @norm_pi_pi(float %angle) \n");
    //strcat(elseDrive, "\n");
    //strcat(elseDrive, "    %posmid   = call float @get_pos_to_middle(%struct.tTrkLocPos* %pos) \n");
    //strcat(elseDrive, "    %width    = call float @get_track_seg_width(%struct.trackSeg* %seg) \n");
    //strcat(elseDrive, "    %corr   = fdiv float %posmid, %width \n");
    //strcat(elseDrive, "    %cangle   = fsub float %nangle, %corr \n");
    //strcat(elseDrive, "\n");
    //strcat(elseDrive, "    store float %cangle, float* %steer \n    ");
    strcat(elseDrive, $3.code);
    strcat(elseDrive, "\n");
    //    ajout_store_manquant();
    // strcat(elseDrive, tmpC);
    strcat(elseDrive, "\n \n    ret void \n");
    strcat(elseDrive, "}\n");
  } else {
    strcpy($$.code, $2.code);
    strcat(elseDrive, "{\n");
    strcat(elseDrive, "\n");
    strcat(elseDrive, $3.code); 
    strcat(elseDrive, "}\n");
  } 
													
  fprintf(driver,"define %s @%s %s\n\n", $1.code, $2.code, elseDrive);
  elseDrive[0] = '\0';} // tester declarator !!
;

%%
#include <stdio.h>
#include <string.h>

extern int column;
extern int yylineno;
extern FILE *yyin;

char *file_name = NULL;

int yyerror (char *s) {
  fflush (stdout);
  fprintf (stderr, "%s:%d:%d: %s\n", file_name, yylineno, column, s);
  return 0;
}


void allExceptDrive(){
  fprintf(driver,"target triple = \"x86_64-unknown-linux-gnu\"\n");

  fprintf(driver,"%%struct.CarElt = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.tInitCar,\n");
  fprintf(driver,"    %%struct.tPublicCar,\n");
  fprintf(driver,"    %%struct.tCarRaceInfo,\n");
  fprintf(driver,"    %%struct.tPrivCar,\n");
  fprintf(driver,"    %%struct.tCarCtrl,\n");
  fprintf(driver,"    %%struct.tCarPitCmd,\n");
  fprintf(driver,"    %%struct.RobotItf*,\n");
  fprintf(driver,"    %%struct.CarElt*\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tInitCar = type {\n");
  fprintf(driver,"    [32 x i8],\n");
  fprintf(driver,"    [32 x i8],\n");
  fprintf(driver,"    [32 x i8],\n");
  fprintf(driver,"    [32 x i8],\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [3 x float],\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    [4 x %%struct.tWheelSpec],\n");
  fprintf(driver,"    %%struct.tVisualAttributes\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.t3Dd = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tWheelSpec = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tVisualAttributes = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [2 x %%struct.t3Dd],\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tPublicCar = type {\n");
  fprintf(driver,"    %%struct.tDynPt,\n");
  fprintf(driver,"    %%struct.tDynPt,\n");
  fprintf(driver,"    [4 x [4 x float]],\n");
  fprintf(driver,"    %%struct.tTrkLocPos,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [4 x %%struct.tPosd]\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tDynPt = type {\n");
  fprintf(driver,"    %%struct.tPosd,\n");
  fprintf(driver,"    %%struct.tPosd,\n");
  fprintf(driver,"    %%struct.tPosd\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tPosd = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tTrkLocPos = type {\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.trackSeg = type {\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    [4 x %%struct.t3Dd],\n");
  fprintf(driver,"    [7 x float],\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.SegExt*,\n");
  fprintf(driver,"    %%struct.trackSurface*,\n");
  fprintf(driver,"    [2 x %%struct.trackBarrier*],\n");
  fprintf(driver,"    %%struct.RoadCam*,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%union.anon.0\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.SegExt = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32*\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.trackSurface = type {\n");
  fprintf(driver,"    %%struct.trackSurface*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.trackBarrier = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.trackSurface*,\n");
  fprintf(driver,"    %%class.v2t\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%class.v2t = type {\n");
  fprintf(driver,"    %%union.anon\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%union.anon = type {\n");
  fprintf(driver,"    %%struct.anon\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.anon = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.RoadCam = type {\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.RoadCam*\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%union.anon.0 = type {\n");
  fprintf(driver,"    %%struct.anon.1\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.anon.1 = type {\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSeg*\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCarRaceInfo = type {\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    i8,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    %%struct.TrackOwnPit*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.CarPenaltyHead\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.TrackOwnPit = type {\n");
  fprintf(driver,"    %%struct.tTrkLocPos,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [4 x %%struct.CarElt*]\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.CarPenaltyHead = type {\n");
  fprintf(driver,"    %%struct.CarPenalty*,\n");
  fprintf(driver,"    %%struct.CarPenalty**\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.CarPenalty = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.anon.2\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.anon.2 = type {\n");
  fprintf(driver,"    %%struct.CarPenalty*,\n");
  fprintf(driver,"    %%struct.CarPenalty**\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tPrivCar = type {\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [32 x i8],\n");
  fprintf(driver,"    [4 x %%struct.tWheelState],\n");
  fprintf(driver,"    [4 x %%struct.tPosd],\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    [10 x float],\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [4 x float],\n");
  fprintf(driver,"    [4 x float],\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.tCollisionState_\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tWheelState = type {\n");
  fprintf(driver,"    %%struct.tPosd,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCollisionState_ = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [3 x float],\n");
  fprintf(driver,"    [3 x float]\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCarCtrl = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [4 x [32 x i8]],\n");
  fprintf(driver,"    [4 x float],\n");
  fprintf(driver,"    i32\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCarPitCmd = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.tCarPitSetup\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCarPitSetup = type {\n");
  fprintf(driver,"    %%struct.tCarPitSetupValue,\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    %%struct.tCarPitSetupValue,\n");
  fprintf(driver,"    %%struct.tCarPitSetupValue,\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [4 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [8 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [2 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x %%struct.tCarPitSetupValue],\n");
  fprintf(driver,"    [3 x i32]\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tCarPitSetupValue = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.RobotItf = type {\n");
  fprintf(driver,"    void (i32, %%struct.tTrack*, i8*, i8**, %%struct.Situation*)*,\n");
  fprintf(driver,"     {}*,\n");
  fprintf(driver,"     {}*,\n");
  fprintf(driver,"     {}*,\n");
  fprintf(driver,"     i32 (i32, %%struct.CarElt*, %%struct.Situation*)*,\n");
  fprintf(driver,"     void (i32)*,\n");
  fprintf(driver,"     i32\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tTrack = type {\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.tTrackPitInfo,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSurface*,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.t3Dd,\n");
  fprintf(driver,"    %%struct.tTrackGraphicInfo\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tTrackPitInfo = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.trackSeg*,\n");
  fprintf(driver,"    %%struct.TrackOwnPit*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tTrackGraphicInfo = type {\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i8*,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    [3 x float],\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i8**,\n");
  fprintf(driver,"    %%struct.tTurnMarksInfo\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.tTurnMarksInfo = type {\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float,\n");
  fprintf(driver,"    float\n");
  fprintf(driver,"}\n");

  fprintf(driver,"\n");

  fprintf(driver,"%%struct.Situation = type {\n");
  fprintf(driver,"    %%struct.tRaceAdmInfo,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    double,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    %%struct.CarElt**\n");
  fprintf(driver,"}\n\n");

  fprintf(driver,"%%struct.tRaceAdmInfo = type {\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i32,\n");
  fprintf(driver,"    i64\n");
  fprintf(driver,"}\n\n");

}

void declarations(){
  int declar = 0; int nom = 0; int cmpt = 0;
  
  for(declar = 0; declar < glob_fonction; declar++){
    cmpt = 0;
    for(nom = declar; nom < glob_fonction; nom++){
      if(strcmp(tabFonctionNom[declar], tabFonctionNom[nom])==0)
	cmpt++;
    }
    if(cmpt <= 1){
      fprintf(driver, "%s", tabFonction[declar]);
      fprintf(driver, "\n");
    }
  }
  //fprintf(driver,"declare float @test_fonction(float %%a, float %%b)\n");
  //fprintf(driver,"declare float @norm_pi_pi(float %%a)\n");
  fprintf(driver,"declare float @get_pos_to_right(%%struct.tTrkLocPos*)\n");
  fprintf(driver,"declare float @get_pos_to_middle(%%struct.tTrkLocPos*)\n");
  fprintf(driver,"declare float @get_pos_to_left(%%struct.tTrkLocPos*)\n");
  fprintf(driver,"declare float @get_pos_to_start(%%struct.tTrkLocPos*)\n");
  fprintf(driver,"declare float @get_track_seg_length(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_width(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_start_width(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_end_width(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_radius(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_right_radius(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_left_radius(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_track_seg_arc(%%struct.trackSeg*)\n");
  fprintf(driver,"declare %%struct.trackSeg* @get_track_seg_next(%%struct.trackSeg*)\n");
  fprintf(driver,"declare float @get_car_yaw(%%struct.CarElt*)\n");

}

void init_hash(){
  int i;
  for (i = 0; i < BUFSIZE; ++i)
    {
      tabHash[i] = NOINIT;
    }
}

void static_declarations(){
  tabHash[hash("%gear")] = ID_INT;
  tabHash[hash("%accelCmd")] = ID_FLOAT;
  tabHash[hash("%steer")] = ID_FLOAT;
  tabHash[hash("%clutchCmd")] = ID_FLOAT;
  tabHash[hash("%brakeCmd")] = ID_FLOAT;
  tabHash[hash("%x")] = RO_FLOAT;
  tabHash[hash("%y")] = RO_FLOAT;
  tabHash[hash("%z")] = RO_FLOAT;
  tabHash[hash("%speedx")] = RO_FLOAT;
  tabHash[hash("%speedy")] = RO_FLOAT;
  tabHash[hash("%speedz")] = RO_FLOAT;
  tabHash[hash("%accelx")] = RO_FLOAT;
  tabHash[hash("%accely")] = RO_FLOAT;
  tabHash[hash("%accelyz")] = RO_FLOAT;
  tabHash[hash("%rpm")] = RO_INT;
  int i=0;
  for (i = 0; i < 5; ++i) {
    static_var[i] = 0;
  }
}

int main (int argc, char *argv[]) {
  FILE *input = NULL;
  //FILE *fopen (const char *path, const char *mode);

  if (argc==2) {
    input = fopen (argv[1], "r");
    file_name = strdup (argv[1]);
    if (input) {
      yyin = input;
    }
    else {
      fprintf (stderr, "%s: Could not open %s\n", *argv, argv[1]);
      return 1;
    }
  }
  else {
    fprintf (stderr, "%s: error: no input file\n", *argv);
    return 1;
  }
  driver = fopen("./drive.ll", "w");
  init_hash();
  static_declarations();
  allExceptDrive();
  yyparse ();
  declarations();
  free (file_name);
  fclose(driver);
  return 0;
}
